package hn.cch.framework.google.guava;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.Weigher;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * LRU：最近最久未使用
 * 基于大小剔除、基于时间剔除、基于引用剔除
 */
public class GuavaCacheTest {

    private static final Logger logger = LoggerFactory.getLogger(GuavaCacheTest.class);


    /**
     * 根据key加载数据
     *
     * @param key
     * @return
     */
    public String loadData(String key) {
        String result = String.format("prefix-%s-suffix", key);
        logger.info("load data:{}", result);
        return result;
    }


    @Test
    public void testLoadingCache() throws ExecutionException {

        LoadingCache<String, String> loadingCache = CacheBuilder.newBuilder().maximumSize(3)
            .build(new CacheLoader<String, String>() {
                @Nonnull
                @Override
                public String load(@Nonnull String key) throws Exception {
                    // 缓存没有命中，就要加载数据
                    return loadData(key);
                }
            });

        String[] keys = {"123", "456", "789", "123", "abc", "123", "456"};
        for (String key : keys) {
            // String result = loadingCache.get(key);
            String result = loadingCache.getUnchecked(key);
        }

    }


    @Test
    public void testCache() throws ExecutionException {
        Cache<String, String> cache = CacheBuilder.newBuilder().maximumSize(3).build();

        String[] keys = {"123", "456", "789", "123", "abc", "123", "456"};
        for (String key : keys) {
            String result = cache.get(key, () -> {
                // 缓存没有命中，就要加载数据
                return loadData(key);
            });
        }
        String key = "key";
        cache.put(key, "value");
        logger.info("key:{},get:{};", key, cache.get(key, () -> "get value"));

    }


    @Test
    public void testCacheWeight() throws ExecutionException {
        Cache<String, String> cache = CacheBuilder.newBuilder().maximumWeight(3)
            .weigher((Weigher<String, String>) (key, value) -> key.length() % 10).build();

        String[] keys = {"1", "22", "333", "4444", "55555", "55555"};
        for (String key : keys) {
            String result = cache.get(key, () -> {
                // 缓存没有命中，就要加载数据
                return loadData(key);
            });
        }


    }

    @Test
    public void testCacheExpire() throws ExecutionException, InterruptedException {
        Cache<String, String> cache = CacheBuilder.newBuilder()
            .expireAfterWrite(5, TimeUnit.SECONDS)
            .expireAfterAccess(3, TimeUnit.SECONDS)
            .build();

        String[] keys = {"111", "222", "111", "222", "333", "333", "333", "222", "111"};
        for (String key : keys) {
            String result = cache.get(key, () -> {
                // 缓存没有命中，就要加载数据
                return loadData(key);
            });
            Thread.sleep(1000);
        }


    }

    @Test
    public void testCacheReference() {
        Cache<String, String> cache = CacheBuilder.newBuilder()
            .weakKeys()
            // .weakValues()
            // .softValues()
            .build();

    }

    @Test
    public void testInvalidate() throws ExecutionException {
        Cache<String, String> cache = CacheBuilder.newBuilder()
            .removalListener((RemovalListener<String, String>) removalNotification -> {

            })
            .maximumSize(3).build();
        String key = "key";
        cache.put(key, "value");
        logger.info("key:{},get:{};", key, cache.get(key, () -> "get value"));
        cache.invalidate(key);
        // cache.invalidateAll(keyList);
        // cache.invalidateAll();
    }

}
